<?php


namespace App\Timer;

use App\Exception\TimerException;
use App\Service\TimerService;
use App\Util\ResultUtil;
use App\Util\UrlUtil;
use Elite\Infrastructure\Helper\Logger;
use Elite\Infrastructure\Server\Request;
use Elite\Infrastructure\Server\Timer\Finish;

/**
 * 定时器基类
 * Class BaseTimer
 * @package App\Timer
 */
abstract class BaseTimer {


    protected $timerFinish;

    /**
     * 无任务等待时长(秒)
     * @var int
     */
    protected $waitInterval = 120;

    /**
     * 无任务时等待次数
     * @var int
     */
    protected $waitTimes = 5;

    /**
     * 有任务下次执行时间(秒)
     * @var int
     */
    protected $nextInterval = 1;

    private $logger;

    public function __construct(Finish $finish, Logger $logger) {
        $this->timerFinish = $finish;
        $this->logger = $logger->getLogger('timer/timer-' . date("Y_m_d") . '.log');
        $this->logger->info("start timer {$finish->getTimerCode()}");
    }

    /**
     * 定时器入口
     * 所有的timer路由的执行方法都指向这个
     * @return Finish
     */
    public function boost() {
        try {
            return $this->checkTimes()->start();
        } catch (\Throwable $exception) {
            $this->timerFinish->setAction(Finish::ACTION_END);
            $this->timerFinish->setTimes(0);
            $this->timerFinish->setResult(ResultUtil::fail($exception->getMessage()));
            $this->logger->error("timer {$this->timerFinish->getTimerCode()} error: {$exception->getMessage()}");
            return $this->timerFinish;
        }
    }

    private function checkTimes() {
        if ($this->timerFinish->getAction() === Finish::ACTION_WAIT) {
            if ($this->timerFinish->getTimes() > $this->waitTimes) {
                $currTimes = $this->timerFinish->getTimes();
                $this->timerFinish->setTimes(0);
                throw new TimerException("over times limit[{$this->waitTimes}] current[{$currTimes}].");
            }
        }
        return $this;
    }

    private function start() {
        $queue = $this->lock($this->timerFinish->getTimerId());
        if (empty($queue)) {
            $this->timerFinish->setAction(Finish::ACTION_WAIT);
            $this->timerFinish->setWaitDelay($this->waitInterval * 1000);
            return $this->timerFinish;
        }
        $result = $this->process($queue);
        $this->finish($queue, $result);
        $this->timerFinish->setAction(Finish::ACTION_NEXT);
        $this->timerFinish->setNextDelay($this->nextInterval * 1000);
        return $this->timerFinish;
    }

    abstract protected function lock($timerId);

    abstract protected function process($lockInfo);

    abstract protected function finish($queue, $result);
}